home *** CD-ROM | disk | FTP | other *** search
/ PC-X 1997 October / pcx14_9710.iso / swag / delphi.swg / 0235_FLI ScreenSave for Delphi 1.0.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-03-04  |  23.2 KB  |  765 lines

  1. {
  2. Hi, This is an easy made screensaver, viewing FLI files from
  3. Autodesk animator, it's not optimized for reading FLC files, since
  4. that would be a larger project, which i dont have enough spare-time
  5. for now!
  6.  
  7. The "Treatframe" and "Getclock" routine was taken from Eirik Pedersens
  8. fli player, found in snipet: "misc". I had to change Treatframe a litle
  9. just to handle the palette. Use at your own risk.
  10.  
  11. There's not much documentation, but if there's so much you don't understand,
  12. send me a mail, and i'll try to answer it as soon as possible!
  13.  
  14.  
  15.  
  16. Tommy Andersen
  17. email: tommy.andersen@dialogue.telemax.no
  18. snail: Tommy Andersen
  19.        Andebuveien 11
  20.        3170  SEM
  21.        Norway
  22. }
  23.  
  24.  
  25. Program Fliplay;
  26.  
  27. Uses
  28.   Forms,
  29.   Unit1 in 'UNIT1.PAS' {Form1};
  30.  
  31. {$R *.RES}
  32.  
  33. Begin
  34.    { Prevent multiple instances }
  35.    IF HPrevinst <> 0 Then Exit;
  36.  
  37.    Application.CreateForm(TForm1, Form1);
  38.    Application.Run;
  39. End.
  40.  
  41. { -------------  Cut out and save as UNIT1.PAS ----------------- }
  42.  
  43. Unit Unit1;
  44.  
  45. Interface
  46.  
  47. Uses
  48.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  49.   Forms, Dialogs;
  50.  
  51. Const
  52.   CLOCK_HZ              = 4608;                   { Frequency of clock }
  53.   MONItoR_HZ            = 70;                     { Frequency of monitor }
  54.   CLOCK_SCALE           = CLOCK_HZ div MONItoR_HZ;
  55.   CDATA                 = $040;                   { Port number of timer 0 }
  56.   CMODE                 = $043;                   { Port number of timers control Word }
  57.   Scale_FLI             = False;                  { Set this to true if saver shall use whole screen }
  58.  
  59. Type
  60.   Big_Buffer_Type = Array[0..65534] of Byte;
  61.   FliHeaderType = Record
  62.                      Size          : Longint;
  63.                      Magic         : Word;
  64.                      Frames        : Word;
  65.                      Width         : Word;
  66.                      Height        : Word;
  67.                      Bitsperpixel  : Word;
  68.                      Flags         : Integer;
  69.                      Speed         : Integer;
  70.                      Nexthead      : Longint;
  71.                      Framesintable : Longint;
  72.                      hfile         : Integer;
  73.                      hframe1offset : Longint;
  74.                      Strokes       : Longint;
  75.                      Session       : Longint;
  76.                      Reserved      : Array [1..88] of Byte;
  77.                   End;
  78.   FrameHeaderType = Record
  79.                        Size   : LongInt;
  80.                        Magic  : Word; { $F1FA }
  81.                        Chunks : Word;
  82.                        Expand : Array[1..8] of Byte;
  83.                     End;
  84.  
  85.  
  86.   TForm1 = Class(TForm)
  87.     OpenDialog1: TOpenDialog;
  88.     Procedure FormCreate(Sender: TObject);
  89.     procedure FormPaint(Sender: TObject);
  90.     procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  91.       Y: Integer);
  92.     procedure FormKeyDown(Sender: TObject; var Key: Word;
  93.       Shift: TShiftState);
  94.   Private
  95.     { Private declarations }
  96.   Public
  97.     { Public declarations }
  98.     Start_Screensaver        : Boolean;
  99.     MouseMovement            : Byte;
  100.     Fli_Filename             : String;
  101.     Screensaver_Ini_filename : String;
  102.     ScreenBitmap             : TBitmap;
  103.  
  104.  
  105.     Flifilestream            : TMemoryStream;
  106.     FliScreenstream          : TMemoryStream;
  107.     Screen_Buffer            : ^Big_Buffer_Type;
  108.     File_Buffer              : ^Big_Buffer_Type;
  109.     FLI_Header               : FLIHeaderType;
  110.     FLI_FrameHeader          : FrameHeaderType;
  111.     FLI_Speed                : Longint;
  112.     FLI_Nexttime             : Longint;
  113.     Fli_FrameNr              : Word;
  114.     FLI_SecondPosition       : Longint;
  115.  
  116.  
  117.     Procedure Get_INI_Filename;
  118.     Procedure Read_INI_Settings;
  119.     Procedure Write_INI_Settings;
  120.  
  121.     Procedure Create_Bitmap;
  122.     Procedure Show_Next_Frame;
  123.     Procedure Load_FLI_File;
  124.     Procedure Kill_FLI_Screensaver;
  125.   End;
  126.  
  127. Var
  128.   Form1: TForm1;
  129.  
  130. Implementation
  131.  
  132. {$R *.DFM}
  133.  
  134. Uses Inifiles;
  135.  
  136.  
  137. Function GetClock:LongInt; Assembler; {Taken from the FLILIB source}
  138. { this routine returns a clock With occassional spikes where time
  139.   will look like its running backwards 1/18th of a second.  The resolution
  140.   of the clock is 1/(18*256) = 1/4608 second.  66 ticks of this clock
  141.   are supposed to be equal to a monitor 1/70 second tick.}
  142. Asm
  143.   mov  ah,0                                         { get tick count from Dos and use For hi 3 Bytes }
  144.   int  01ah                                         { lo order count in DX, hi order in CX }
  145.   mov  ah,dl
  146.   mov  dl,dh
  147.   mov  dh,cl
  148.  
  149.   mov  al,0                                         { read lo Byte straight from timer chip }
  150.   out  CMODE,al                                         { latch count }
  151.   mov  al,1
  152.   out  CMODE,al                                         { set up to read count }
  153.   in   al,CDATA                                         { read in lo Byte (and discard) }
  154.   in   al,CDATA                                         { hi Byte into al }
  155.   neg  al                                         { make it so counting up instead of down }
  156. End;
  157.  
  158. Procedure TForm1.Get_INI_Filename;
  159. Var
  160.   Buffer : Array[0..255] of Char;
  161.   Size   : Word;
  162.  
  163. Begin
  164.    Size := GetSystemDirectory(Buffer, 256);
  165.    IF Size <> 0 Then
  166.    Begin
  167.       Screensaver_Ini_filename := StrPas(Buffer);
  168.       Screensaver_Ini_filename[0] := Chr(Size);
  169.    End
  170.     Else Screensaver_Ini_filename := 'C:\';
  171.  
  172.  
  173.  
  174.    { Make sure filename got the last expected slash }
  175.    IF Screensaver_Ini_filename[Length(Screensaver_Ini_filename)] <> '\' Then
  176.       Screensaver_Ini_filename := Screensaver_Ini_filename + '\';
  177.  
  178.  
  179.    Screensaver_Ini_filename := Screensaver_Ini_filename + 'FLIPLAY.INI';
  180. End;
  181.  
  182. Procedure TForm1.Write_INI_Settings;
  183. Var
  184.   Inifile : TInifile;
  185.  
  186. Begin
  187.    Inifile := TInifile.Create(Screensaver_Ini_filename);
  188.    Inifile.WriteString('FLI-Screensaver', 'Filename', Fli_Filename);
  189.    Inifile.Free;
  190. End;
  191.  
  192. Procedure TForm1.Read_INI_Settings;
  193. Var
  194.   Inifile : TInifile;
  195.  
  196. Begin
  197.    Inifile := TInifile.Create(Screensaver_Ini_filename);
  198.    Fli_Filename := Inifile.ReadString('FLI-Screensaver', 'Filename', '');
  199.    Inifile.Free;
  200. End;
  201.  
  202. Procedure TForm1.Load_FLI_File;
  203. Var
  204.   Temp : Word;
  205.  
  206. Begin
  207.    Fli_FrameNr := 0;
  208.    FliFileStream.Clear;
  209.  
  210.    IF FileExists(Fli_Filename) Then
  211.    Begin
  212.       Try
  213.         FliFileStream.LoadFromFile(Fli_Filename);
  214.       Except
  215.         FliFileStream.Clear;
  216.       End;
  217.  
  218.       IF (FliFileStream.Size > 128) Then
  219.       Begin
  220.          FliFileStream.Seek(0, 0);
  221.          Temp := FliFileStream.Read(Fli_Header, 128);
  222.  
  223.          IF (Temp = 128) and (Fli_Header.Magic = $AF11) Then
  224.          Begin
  225.             { Ok }
  226.             FLI_Speed := Fli_Header.Speed;
  227.             FLI_Speed := FLI_Speed*CLOCK_SCALE;
  228.             FLI_NextTime := 0;
  229.          End
  230.           Else FliFileStream.Clear;
  231.  
  232.       End;
  233.    End;
  234. End;
  235.  
  236. Procedure TForm1.Create_Bitmap;
  237. Type
  238.   BitmapHeader = Record
  239.                     ID    : Word;
  240.                     FSize : LongInt;
  241.                     Ver   : LongInt;
  242.                     Image : LongInt;
  243.                     Misc  : LongInt;
  244.                     Width : LongInt;
  245.                     Height: LongInt;
  246.                     Num   : Word;
  247.                     Bits  : Word;
  248.                     Comp  : LongInt;
  249.                     ISize : LongInt;
  250.                     XRes  : LongInt;
  251.                     YRes  : LongInt;
  252.                     PSize : LongInt;
  253.                     Res   : LongInt;
  254.                  End;
  255.  
  256. Var
  257.   BmpHeader : BitmapHeader;
  258.   T, myByte : Byte;
  259.   MSize     : LongInt;
  260.  
  261.  
  262. Begin
  263.    FLIScreenStream.Clear;
  264.  
  265.  
  266.    MSize := 64000;
  267.    MSize := MSize + 1024;
  268.    MSize := MSize + 54;
  269.  
  270.    BmpHeader.ID          := 19778;
  271.    BmpHeader.FSize       := MSize;
  272.    BmpHeader.Ver         := 0;
  273.    BmpHeader.Image       := 54 + (256*4);
  274.    BmpHeader.Misc        := 40;
  275.    BmpHeader.Width       := 320;
  276.    BmpHeader.Height      := 200;
  277.    BmpHeader.Num         := 1;
  278.    BmpHeader.Bits        := 8;
  279.    BmpHeader.Comp        := bi_RGB;
  280.    BmpHeader.ISize       := BmpHeader.FSize - BmpHeader.Image;
  281.    BmpHeader.XRes        := 0;
  282.    BmpHeader.YRes        := 0;
  283.    BmpHeader.Res         := 0;
  284.  
  285.    FLIScreenStream.Write(BmpHeader.ID, 2);
  286.    FLIScreenStream.Write(BmpHeader.FSize, 4);
  287.    FLIScreenStream.Write(BmpHeader.Ver, 4);
  288.    FLIScreenStream.Write(BmpHeader.Image, 4);
  289.    FLIScreenStream.Write(BmpHeader.Misc, 4);
  290.    FLIScreenStream.Write(BmpHeader.Width, 4);
  291.    FLIScreenStream.Write(BmpHeader.Height, 4);
  292.    FLIScreenStream.Write(BmpHeader.Num, 2);
  293.    FLIScreenStream.Write(BmpHeader.Bits, 2);
  294.    FLIScreenStream.Write(BmpHeader.Comp, 4);
  295.    FLIScreenStream.Write(BmpHeader.ISize, 4);
  296.    FLIScreenStream.Write(BmpHeader.XRes, 4);
  297.    FLIScreenStream.Write(BmpHeader.YRes, 4);
  298.    FLIScreenStream.Write(BmpHeader.Res, 4);
  299.  
  300.  
  301.    FLIScreenStream.Seek(54, 0);
  302.    { Create palette }
  303.    For T := 0 To 255 do
  304.    Begin
  305.       { Blue }
  306.       myByte := T;
  307.       FLIScreenStream.Write(myByte, 1);
  308.  
  309.       { Green }
  310.       FLIScreenStream.Write(myByte, 1);
  311.  
  312.       { Red }
  313.       FLIScreenStream.Write(myByte, 1);
  314.  
  315.       myByte := 0;
  316.       FLIScreenStream.Write(myByte, 1);
  317.    End;
  318.  
  319.  
  320.    FillChar(Screen_Buffer^, 64000, 0);
  321.    FLIScreenStream.Write(Screen_Buffer^, 64000);
  322. End;
  323.  
  324. Procedure TForm1.Kill_FLI_Screensaver;
  325. Begin
  326.    Freemem(Screen_Buffer, 64000);
  327.    Freemem(File_Buffer, 65535);
  328.    Flifilestream.Free;
  329.    FliScreenstream.Free;
  330.    ScreenBitmap.Free;
  331.    Halt(0);
  332. End;
  333.  
  334. Procedure TForm1.FormCreate(Sender: TObject);
  335. Var
  336.   Param : String;
  337.   S     : String;
  338.  
  339. Begin
  340.    Flifilestream    := TMemoryStream.Create;
  341.    FliScreenstream  := TMemoryStream.Create;
  342.    ScreenBitmap     := TBitmap.Create;
  343.  
  344.  
  345.    Param := Uppercase( Paramstr(1) );
  346.    Caption := 'FLI screensaver, made by Tommy Andersen!';
  347.    Application.Title := Caption;
  348.  
  349.  
  350.    Getmem(Screen_Buffer, 64000);
  351.    Getmem(File_Buffer, 65535);
  352.  
  353.  
  354.    Get_INI_Filename;
  355.    Read_INI_Settings;
  356.  
  357.  
  358.    { Config screensaver? }
  359.    IF Param = '/C' Then
  360.    Begin
  361.       { Yes }
  362.       Start_Screensaver := False;
  363.       Windowstate := wsMinimized;
  364.  
  365.  
  366.       S     := '';
  367.       Param := FLI_Filename;
  368.       While Pos('\', Param) > 0 do
  369.       Begin
  370.          S := S + Copy(Param, 1, Pos('\', Param));
  371.          Delete(Param, 1, Pos('\', Param));
  372.       End;
  373.       Opendialog1.Initialdir := S;
  374.       Opendialog1.Filename := Param;
  375.  
  376.  
  377.       Opendialog1.Filter := 'FLI files|*.FLI|All files|*.*';
  378.       IF Opendialog1.Execute Then
  379.       Begin
  380.          FLI_Filename := Opendialog1.Filename;
  381.          Write_INI_Settings;
  382.       End;
  383.  
  384.  
  385.       Kill_FLI_Screensaver;
  386.    End
  387.     Else
  388.      Begin
  389.         { No! Start screensaver! }
  390.         Create_Bitmap;
  391.         Load_FLI_File;
  392.  
  393.  
  394.         Start_Screensaver := True;
  395.         Windowstate       := wsMaximized;
  396. {
  397.         Formstyle         := fsStayOnTop;
  398. }
  399.         Borderstyle       := bsNone;
  400.         Color             := clBlack;
  401.         MouseMovement     := 0;
  402.      End;
  403.  
  404. End;
  405.  
  406. Procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y : Integer);
  407. Begin
  408.    IF MouseMovement > 2 Then Kill_FLI_Screensaver;
  409.    Inc(MouseMovement);
  410. End;
  411.  
  412. Procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  413. Begin
  414.    Kill_FLI_Screensaver;
  415. End;
  416.  
  417. Procedure TForm1.Show_Next_Frame;
  418. Type
  419.   Paltype = Array[0..767] of Byte;
  420.  
  421. Var
  422.   Temp    : Word;
  423.   Nextpos : Longint;
  424.   Palette : ^Paltype;
  425.   Paladdr : Word;
  426.  
  427. Procedure TreatFrame(Var Buffer, ScreenBuffer, Palette; Chunks:Word); Assembler;
  428. { this is the 'workhorse' routine that takes a frame and put it on the screen }
  429. { chunk by chunk }
  430. Label
  431.   Color_Loop, Copy_Bytes, Copy_Bytes2, Exit, Fli_Black, Fli_Brun, Fli_Color,
  432.   Fli_Copy, Fli_Lc, Fli_Loop, Jump_Over, Line_Loop, Line_Loop2, Next_Line,
  433.   Next_Line2, Pack_Loop, Pack_Loop2, C_Loop;
  434.  
  435. Asm
  436.   Cli
  437.  
  438.   push ds
  439.   lds  si,Buffer                                 { let DS:SI point at the frame to be drawn }
  440.  
  441. Fli_Loop:                                        { main loop that goes through all the chunks in a frame }
  442.   cmp  Chunks,0                                  { are there any more chunks to draw? }
  443.   je   Exit
  444.   dec  Chunks                                    { decrement Chunks For the chunk to process now }
  445.  
  446.   mov  ax,[Word ptr ds:si+4]                     { let AX have the ChunkType }
  447.   add  si,6                                      { skip the ChunkHeader }
  448.  
  449.   cmp  ax,0Bh                                    { is it a FLI_COLor chunk? }
  450.   je   Fli_Color
  451.   cmp  ax,0Ch                                    { is it a FLI_LC chunk? }
  452.   je   Fli_Lc
  453.   cmp  ax,0Dh                                    { is it a FLI_BLACK chunk? }
  454.   je   Fli_Black
  455.   cmp  ax,0Fh                                    { is it a FLI_BRUN chunk? }
  456.   je   Fli_Brun
  457.   cmp  ax,10h                                    { is it a FLI_COPY chunk? }
  458.   je   Fli_Copy
  459.   jmp  Fli_Loop                                  { This command should not be necessary since the Program should make one - }
  460.                                                  { - of the other jumps }
  461.  
  462. Fli_Color:
  463.   mov  bx,[Word ptr ds:si]                       { number of packets in this chunk (allways 1?) }
  464.   add  si,2                                      { skip the NumberofPackets }
  465.   mov  al,0                                      { start at color 0 }
  466.   xor  cx,cx                                     { reset CX }
  467.  
  468. Color_Loop:
  469.   or   bx,bx                                     { set flags }
  470.   jz   Fli_Loop                                  { Exit if no more packages }
  471.   dec  bx                                        { decrement NumberofPackages For the package to process now }
  472.  
  473.   mov  cl,[Byte ptr ds:si+0]                     { first Byte in packet tells how many colors to skip }
  474.   add  al,cl                                     { add the skiped colors to the start to get the new start }
  475.  
  476.   mov  cl,[Byte ptr ds:si+1]                     { next Byte in packet tells how many colors to change }
  477.   or   cl,cl                                     { set the flags }
  478.   jnz  Jump_Over                                 { if NumberstoChange=0 then NumberstoChange=256 }
  479.   inc  ch                                        { CH=1 and CL=0 => CX=256 }
  480. Jump_Over:
  481.   add  al,cl                                     { update the color to start at }
  482.   mov  di,cx                                     { since each color is made of 3 Bytes (Red, Green & Blue) we have to - }
  483.   shl  cx,1                                      { - multiply CX (the data counter) With 3 }
  484.   add  cx,di                                     { - CX = old_CX shl 1 + old_CX   (the fastest way to multiply With 3) }
  485.   add  si,2                                      { skip the NumberstoSkip and NumberstoChange Bytes }
  486.  
  487.  
  488.   { Find start position }
  489.   Les  di, Palette
  490.   Mov  CL, AL
  491. @LLL:
  492.   Cmp  CL, 0
  493.   Je   C_Loop
  494.   Dec  CL
  495.   Add  di, 3
  496.   Jmp  @LLL
  497.  
  498. C_Loop:
  499.   Cmp  CX, 0
  500.   Je   Color_Loop
  501.   Dec  CX
  502.   Mov  AL, [Byte ptr DS:SI]
  503.   Add  AL, AL
  504.   Add  AL, AL
  505.   Mov  [Byte ptr ES:DI], AL
  506.   Inc  SI
  507.   Inc  DI
  508.   Jmp  C_Loop
  509.  
  510.  
  511. Fli_Lc:
  512.   Les  di, ScreenBuffer
  513.  
  514.   mov  di,[Word ptr ds:si+0]                     { put LinestoSkip into DI - }
  515.   mov  ax,di                                     { - to get the offset address to this line we have to multiply With 320 - }
  516.   shl  ax,8                                      { - DI = old_DI shl 8 + old_DI shl 6 - }
  517.   shl  di,6                                      { - it is the same as DI = old_DI*256 + old_DI*64 = old_DI*320 - }
  518.   add  di,ax                                     { - but this way is faster than a plain mul }
  519.   mov  bx,[Word ptr ds:si+2]                     { put LinestoChange into BX }
  520.   add  si,4                                      { skip the LinestoSkip and LinestoChange Words }
  521.   xor  cx,cx                                     { reset cx }
  522.  
  523. Line_Loop:
  524.   or   bx,bx                                     { set flags }
  525.   jz  Fli_Loop                                   { Exit if no more lines to change }
  526.   dec  bx
  527.  
  528.   mov  dl,[Byte ptr ds:si]                       { put PacketsInLine into DL }
  529.   inc  si                                        { skip the PacketsInLine Byte }
  530.   push di                                        { save the offset address of this line }
  531.  
  532. Pack_Loop:
  533.   or   dl,dl                                     { set flags }
  534.   jz   Next_Line                                 { Exit if no more packets in this line }
  535.   dec  dl
  536.   mov  cl,[Byte ptr ds:si+0]                     { put BytestoSkip into CL }
  537.   add  di,cx                                     { update the offset address }
  538.   mov  cl,[Byte ptr ds:si+1]                     { put BytesofDatatoCome into CL }
  539.   or   cl,cl                                     { set flags }
  540.   jns  Copy_Bytes                                { no SIGN means that CL number of data is to come - }
  541.                                                  { - else the next data should be put -CL number of times }
  542.   mov  al,[Byte ptr ds:si+2]                     { put the Byte to be Repeated into AL }
  543.   add  si,3                                      { skip the packet }
  544.   neg  cl                                        { Repeat -CL times }
  545.   rep  stosb
  546.   jmp  Pack_Loop                                 { finish With this packet }
  547.  
  548. Copy_Bytes:
  549.   add  si,2                                      { skip the two count Bytes at the start of the packet }
  550.   rep  movsb
  551.   jmp  Pack_Loop                                 { finish With this packet }
  552.  
  553. Next_Line:
  554.   pop  di                                        { restore the old offset address of the current line }
  555.   add  di,320                                    { offset address to the next line }
  556.   jmp  Line_Loop
  557.  
  558.  
  559. Fli_Black:
  560.   Les  di, ScreenBuffer
  561.  
  562.   xor  di,di
  563.   mov  cx,32000                                  { number of Words in a screen }
  564.   xor  ax,ax                                     { color 0 is to be put on the screen }
  565.   rep  stosw
  566.   jmp  Fli_Loop                                  { jump back to main loop }
  567.  
  568.  
  569. Fli_Brun:
  570.   Les  di, ScreenBuffer
  571.  
  572.   xor  di,di
  573.   mov  bx,200                                    { numbers of lines in a screen }
  574.   xor  cx,cx
  575.  
  576. Line_Loop2:
  577.   mov  dl,[Byte ptr ds:si]                       { put PacketsInLine into DL }
  578.   inc  si                                        { skip the PacketsInLine Byte }
  579.   push di                                        { save the offset address of this line }
  580.  
  581. Pack_Loop2:
  582.   or   dl,dl                                     { set flags }
  583.   jz   Next_Line2                                { Exit if no more packets in this line }
  584.   dec  dl
  585.   mov  cl,[Byte ptr ds:si]                       { put BytesofDatatoCome into CL }
  586.   or   cl,cl                                     { set flags }
  587.   js   Copy_Bytes2                               { SIGN meens that CL number of data is to come - }
  588.                                                  { - else the next data should be put -CL number of times }
  589.   mov  al,[Byte ptr ds:si+1]                     { put the Byte to be Repeated into AL }
  590.   add  si,2                                      { skip the packet }
  591.   rep  stosb
  592.   jmp  Pack_Loop2                                { finish With this packet }
  593.  
  594. Copy_Bytes2:
  595.   inc  si                                        { skip the count Byte at the start of the packet }
  596.   neg  cl                                        { Repeat -CL times }
  597.   rep  movsb
  598.   jmp  Pack_Loop2                                { finish With this packet }
  599.  
  600. Next_Line2:
  601.   pop  di                                        { restore the old offset address of the current line }
  602.   add  di,320                                    { offset address to the next line }
  603.   dec  bx                                        { any more lines to draw? }
  604.   jnz  Line_Loop2
  605.   jmp  Fli_Loop                                  { jump back to main loop }
  606.  
  607.  
  608. Fli_Copy:
  609.   Les  di, ScreenBuffer
  610.  
  611.   xor  di,di
  612.   mov  cx,32000                                  { number of Words in a screen }
  613.   rep  movsw
  614.   jmp  Fli_Loop                                  { jump back to main loop }
  615.  
  616.  
  617. Exit:
  618.   mov  ax, 0
  619.   mov  es, ax
  620.   pop  ds
  621.  
  622.   Sti
  623. end;
  624.  
  625. Procedure ReadPalette;
  626. Var
  627.   T, Zero : Byte;
  628.  
  629. Begin
  630.    FLIScreenstream.Seek(54, 0);
  631.    For T := 0 to 255 do
  632.    Begin
  633.       FLIScreenStream.Read(Palette^[T*3+2], 1); { Blue }
  634.       FLIScreenStream.Read(Palette^[T*3+1], 1); { Green }
  635.       FLIScreenStream.Read(Palette^[T*3], 1); { Red }
  636.       FLIScreenStream.Read(Zero, 1);         { Zero }
  637.    End;
  638. End;
  639.  
  640. Procedure WritePalette;
  641. Var
  642.   T, Zero : Byte;
  643.  
  644. Begin
  645.    Zero := 0;
  646.  
  647.    FLIScreenStream.Seek(54, 0);
  648.    For T := 0 to 255 do
  649.    Begin
  650.       FLIScreenStream.Write(Palette^[T*3+2], 1); { Blue }
  651.       FLIScreenStream.Write(Palette^[T*3+1], 1); { Green }
  652.       FLIScreenStream.Write(Palette^[T*3], 1); { Red }
  653.       FLIScreenStream.Write(Zero, 1);         { Zero }
  654.    End;
  655. End;
  656.  
  657. Procedure Write_To_Screen;
  658. Var
  659.   Y : Word;
  660.  
  661. Begin
  662.    FLIScreenStream.Seek(1078, 0);
  663.  
  664.    For Y := 199 downto 0 do
  665.    Begin
  666.       FLIScreenStream.Write(Screen_Buffer^[Y*320], 320);
  667.    End;
  668. End;
  669.  
  670.  
  671. Begin
  672.    IF GetClock < FLI_Nexttime Then Exit;
  673.  
  674.  
  675.    IF (FliFileStream.Size > 128) Then
  676.    Begin
  677.       FillChar(FLI_FrameHeader, 16, 0);
  678.       FliFileStream.Read(FLI_FrameHeader.Size, 4);
  679.       FliFileStream.Read(FLI_FrameHeader.Magic, 2);
  680.       FliFileStream.Read(FLI_FrameHeader.Chunks, 2);
  681.       FliFileStream.Read(FLI_FrameHeader.Expand, 8);
  682.  
  683.       IF (FLI_FrameHeader.Magic = $F1FA) Then
  684.       Begin
  685.          FLI_FrameHeader.Size := FLI_FrameHeader.Size - 16;
  686.          FliFileStream.Read(File_Buffer^, FLI_FrameHeader.Size);
  687.  
  688.          Getmem(Palette, 768);
  689.          Paladdr := Seg(Palette^);
  690.          ReadPalette;
  691.          TreatFrame(File_Buffer^, Screen_Buffer^, Palette^, FLI_FrameHeader.Chunks);
  692.          WritePalette;
  693.          Freemem(Palette, 768);
  694.  
  695.          Write_To_Screen;
  696.  
  697.  
  698.          IF FLI_FrameNr = 0 Then
  699.          Begin
  700.             FLI_SecondPosition := FliFileStream.Position;
  701.          End;
  702.  
  703.  
  704.          Inc(Fli_FrameNr);
  705.          IF Fli_FrameNr > FLI_Header.Frames Then
  706.          Begin
  707.             FliFileStream.Seek(FLI_SecondPosition, 0);
  708.             Fli_FrameNr := 1;
  709.          End;
  710.  
  711.  
  712.          FLI_NextTime := GetClock + FLI_Speed;
  713.       End;
  714.    End;
  715. End;
  716.  
  717. Procedure TForm1.FormPaint(Sender: TObject);
  718. Begin
  719.    IF not Start_Screensaver Then Exit;
  720.    Start_Screensaver := False;
  721.  
  722.    While True do
  723.    Begin
  724.       Show_Next_Frame;
  725.  
  726.  
  727.       FLIScreenStream.Seek(0, 0);
  728.       Try
  729.         ScreenBitmap.LoadFromStream(FLIScreenStream);
  730.       Except
  731.       End;
  732.  
  733.       IF not Scale_FLI Then Canvas.Draw((Screen.Width div 2) - 160, (Screen.Height div 2) - 100, ScreenBitmap)
  734.          Else Canvas.StretchDraw(ClientRect, ScreenBitmap);
  735.  
  736.       Application.ProcessMessages;
  737.    End;
  738. End;
  739.  
  740. End.
  741.  
  742. { -------------  Cut out and save as UNIT1.DFM ----------------- }
  743.  
  744. object Form1: TForm1
  745.   Left = 216
  746.   Top = 168
  747.   Width = 435
  748.   Height = 300
  749.   Caption = 'Form1'
  750.   Font.Color = clWindowText
  751.   Font.Height = -13
  752.   Font.Name = 'System'
  753.   Font.Style = []
  754.   PixelsPerInch = 96
  755.   OnCreate = FormCreate
  756.   OnKeyDown = FormKeyDown
  757.   OnMouseMove = FormMouseMove
  758.   OnPaint = FormPaint
  759.   TextHeight = 16
  760.   object OpenDialog1: TOpenDialog
  761.     Left = 4
  762.     Top = 4
  763.   end
  764. end
  765.